﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Babel.Parser;
using Babel;
using dragonangel.phpProject.Language.DSL.Parser;

namespace dragonangel.phpProject.Language
{
    public static class TokenMapping
    {
        #region keywords

        private static IDictionary<string, string> builtInFunction = new Dictionary<string, string>();

        public static readonly string begin_code = "<?";
        public static readonly string end_code = "?>";
        public static readonly string alternate_begin_code = "<?php";
        public static readonly string kw_class = "class";
        public static readonly string kw_function = "function";
        public static readonly string kw_interface = "interface";
        public static readonly string kw_null = "null";
        public static readonly string kw_abstract = "abstract";
        public static readonly string kw_if = "if";
        public static readonly string kw_else = "else";
        public static readonly string kw_elseif = "elseif";
        public static readonly string kw_while = "while";
        public static readonly string kw_for = "for";
        public static readonly string kw_continue = "continue";
        public static readonly string kw_break = "break";
        public static readonly string kw_return = "return";
        public static readonly string kw_foreach = "foreach";
        public static readonly string kw_as = "as";
        public static readonly string kw_echo = "echo";
        public static readonly string kw_switch = "switch";
        public static readonly string kw_case = "case";
        public static readonly string kw_default = "default";
        public static readonly string kw_static = "static";
        public static readonly string kw_int = "int";
        public static readonly string kw_void = "void";
        public static readonly string kw_global = "global";
        public static readonly string kw_public = "public";
        public static readonly string kw_protected = "protected";
        public static readonly string kw_private = "private";
        public static readonly string kw_var = "var";
        public static readonly string kw_include = "include";
        public static readonly string kw_includeonce = "include_once";
        public static readonly string kw_require = "require";
        public static readonly string kw_requireonce = "require_once";
        public static readonly string kw_this = "$this";
        public static readonly string kw_parent = "parent";
        public static readonly string kw_new = "new";
        public static readonly string kw_throw = "throw";
        public static readonly string op_accessor = "->";
        public static readonly string op_classaccessor = "::";
        public static readonly string kw_inherit = "extends";
        public static readonly string kw_implement = "implements";
        public static readonly string simplequote = "'";
        public static readonly string quote = "\"";
        public static readonly string kw_true = "true";
        public static readonly string kw_false = "false";
        public static readonly string op_eq = "==";
        public static readonly string op_neq = "!=";
        public static readonly string op_typeeq = "===";
        public static readonly string op_gt = ">";
        public static readonly string op_gte = ">=";
        public static readonly string op_lt = "<";
        public static readonly string op_lte = "<=";
        public static readonly string op_ampamp = "&&";
        public static readonly string op_barbar = "||";
        public static readonly string kw_instanceof = "instanceof";
        public static readonly string op_selfconcat = ".=";
        public static readonly string op_map = "=>";

        #endregion

        static TokenMapping()
        {
            builtInFunction.Add("function_exists", "returns true if the function exists");
            builtInFunction.Add("array", "Creates a new array");
            builtInFunction.Add("count", "returns the number of element in the variable or array");
            builtInFunction.Add("get_class", "returns the name of the class");
            builtInFunction.Add("in_array", "returns true if an element is in the specified array");
            builtInFunction.Add("isset", "returns true if the variable is set or if the element exists in an array");
            builtInFunction.Add("md5", "return a unique identifier");
            builtInFunction.Add("substr", "Returns the string from the offset with the length specified");
            builtInFunction.Add("strpos", "Returns the position of a string in an other");
            builtInFunction.Add("strstr", "");
            builtInFunction.Add("strrev", "Returns the string reversed (the first caracter becomes the last, ...)");
            builtInFunction.Add("stripos", "Returns the position of a string in an other without taking care about case");
            builtInFunction.Add("strlen", "Returns the length of a string");
            builtInFunction.Add("unset", "Unsets a variable or removes an element in an array");
        }

        public static IList<string> GetTokens(Tokens token)
        {
            List<string> list = new List<string>();
            switch (token)
            {
                case Tokens.BEGIN_CODE:
                    list.Add(begin_code);
                    break;
                case Tokens.END_CODE:
                    list.Add(end_code);
                    break;
                case Tokens.ALTERNATE_BEGIN_CODE:
                    list.Add(alternate_begin_code);
                    break;
                case Tokens.KWCLASS:
                    list.Add(kw_class);
                    break;
                case Tokens.KWFUNCTION:
                    list.Add(kw_function);
                    break;
                case Tokens.KWINTERFACE:
                    list.Add(kw_interface);
                    break;
                case Tokens.KWNULL:
                    list.Add(kw_null);
                    break;
                case Tokens.KWABSTRACT:
                    list.Add(kw_abstract);
                    break;
                case Tokens.KWIF:
                    list.Add(kw_if);
                    break;
                case Tokens.KWELSE:
                    list.Add(kw_else);
                    break;
                case Tokens.KWELSEIF:
                    list.Add(kw_elseif);
                    break;
                case Tokens.KWWHILE:
                    list.Add(kw_while);
                    break;
                case Tokens.KWFOR:
                    list.Add(kw_for);
                    break;
                case Tokens.KWCONTINUE:
                    list.Add(kw_continue);
                    break;
                case Tokens.KWBREAK:
                    list.Add(kw_break);
                    break;
                case Tokens.KWRETURN:
                    list.Add(kw_return);
                    break;
                case Tokens.KWFOREACH:
                    list.Add(kw_foreach);
                    break;
                case Tokens.KWAS:
                    list.Add(kw_as);
                    break;
                case Tokens.KWECHO:
                    list.Add(kw_echo);
                    break;
                case Tokens.KWSWITCH:
                    list.Add(kw_switch);
                    break;
                case Tokens.KWCASE:
                    list.Add(kw_case);
                    break;
                case Tokens.KWDEFAULT:
                    list.Add(kw_default);
                    break;
                case Tokens.KWSTATIC:
                    list.Add(kw_static);
                    break;
                case Tokens.KWINT:
                    list.Add(kw_int);
                    break;
                case Tokens.KWVOID:
                    list.Add(kw_void);
                    break;
                case Tokens.KWGLOBAL:
                    list.Add(kw_global);
                    break;
                case Tokens.KWPUBLIC:
                    list.Add(kw_public);
                    break;
                case Tokens.KWPROTECTED:
                    list.Add(kw_protected);
                    break;
                case Tokens.KWPRIVATE:
                    list.Add(kw_private);
                    break;
                case Tokens.KWVAR:
                    list.Add(kw_var);
                    break;
                case Tokens.KWINCLUDE:
                    list.Add(kw_include);
                    break;
                case Tokens.KWINCLUDEONCE:
                    list.Add(kw_includeonce);
                    break;
                case Tokens.KWREQUIRE:
                    list.Add(kw_require);
                    break;
                case Tokens.KWREQUIREONCE:
                    list.Add(kw_requireonce);
                    break;
                case Tokens.KWTHIS:
                    list.Add(kw_this);
                    break;
                case Tokens.KWPARENT:
                    list.Add(kw_parent);
                    break;
                case Tokens.KWNEW:
                    list.Add(kw_new);
                    break;
                case Tokens.KWTHROW:
                    list.Add(kw_throw);
                    break;
                case Tokens.ACCESSOR:
                    list.Add(op_accessor);
                    break;
                case Tokens.CLASSACCESSOR:
                    list.Add(op_classaccessor);
                    break;
                case Tokens.INHERIT:
                    list.Add(kw_inherit);
                    break;
                case Tokens.IMPLEMENT:
                    list.Add(kw_implement);
                    break;
                case Tokens.SIMPLEQUOTE:
                    list.Add(simplequote);
                    break;
                case Tokens.QUOTE:
                    list.Add(quote);
                    break;
                case Tokens.KWTRUE:
                    list.Add(kw_true);
                    break;
                case Tokens.KWFALSE:
                    list.Add(kw_true);
                    break;
                case Tokens.BUILTIN_FUNCTION:
                    list.AddRange(builtInFunction.Keys);
                    break;
                case Tokens.EQ:
                    list.Add(op_eq);
                    break;
                case Tokens.NEQ:
                    list.Add(op_neq);
                    break;
                case Tokens.TYPEEQ:
                    list.Add(op_typeeq);
                    break;
                case Tokens.GT:
                    list.Add(op_gt);
                    break;
                case Tokens.GTE:
                    list.Add(op_gte);
                    break;
                case Tokens.LT:
                    list.Add(op_lt);
                    break;
                case Tokens.LTE:
                    list.Add(op_lte);
                    break;
                case Tokens.AMPAMP:
                    list.Add(op_ampamp);
                    break;
                case Tokens.BARBAR:
                    list.Add(op_barbar);
                    break;
                case Tokens.KWINSTANCEOF:
                    list.Add(kw_instanceof);
                    break;
                case Tokens.SELFCONCAT:
                    list.Add(op_selfconcat);
                    break;
                case Tokens.MAP:
                    list.Add(op_map);
                    break;
                default:
                    break;
            }
            return list;
        }

        public static Tokens GetToken(string text)
        {
            if (builtInFunction.ContainsKey(text))
                return Tokens.BUILTIN_FUNCTION;
            switch (text[0])
            {
                case '$':
                    if (text == kw_this) return Tokens.KWTHIS;
                    return Tokens.VARIABLE;
                case 'a':
                    if (text == kw_as) return Tokens.KWAS;
                    if (text == kw_abstract) return Tokens.KWABSTRACT;
                    break;
                case 'b':
                    if (text == kw_break) return Tokens.KWBREAK;
                    break;
                case 'c':
                    if (text == kw_continue) return Tokens.KWCONTINUE;
                    if (text == kw_class) return Tokens.KWCLASS;
                    if (text == kw_case) return Tokens.KWCASE;
                    break;
                case 'd':
                    if (text == kw_default) return Tokens.KWDEFAULT;
                    break;
                case 'e':
                    if (text == kw_echo) return Tokens.KWECHO;
                    if (text == kw_else) return Tokens.KWELSE;
                    if (text == kw_elseif) return Tokens.KWELSEIF;
                    break;
                case 'f':
                    if (text == kw_for) return Tokens.KWFOR;
                    if (text == kw_function) return Tokens.KWFUNCTION;
                    if (text == kw_false) return Tokens.KWFALSE;
                    if (text == kw_foreach) return Tokens.KWFOREACH;
                    break;
                case 'g':
                    if (text == kw_global) return Tokens.KWGLOBAL;
                    break;
                case 'i':
                    if (text == kw_if) return Tokens.KWIF;
                    if (text == kw_int) return Tokens.KWINT;
                    if (text == kw_include) return Tokens.KWINCLUDE;
                    if (text == kw_includeonce) return Tokens.KWINCLUDEONCE;
                    if (text == kw_interface) return Tokens.KWINTERFACE;
                    if (text == kw_instanceof) return Tokens.KWINSTANCEOF;
                    break;
                case 'n':
                    if (text == kw_new) return Tokens.KWNEW;
                    if (text == kw_null) return Tokens.KWNULL;
                    break;
                case 'p':
                    if (text == kw_public) return Tokens.KWPUBLIC;
                    if (text == kw_parent) return Tokens.KWPARENT;
                    if (text == kw_protected) return Tokens.KWPROTECTED;
                    if (text == kw_private) return Tokens.KWPRIVATE;
                    break;
                case 'r':
                    if (text == kw_return) return Tokens.KWRETURN;
                    if (text == kw_require) return Tokens.KWREQUIRE;
                    if (text == kw_requireonce) return Tokens.KWREQUIREONCE;
                    break;
                case 's':
                    if (text == kw_static) return Tokens.KWSTATIC;
                    if (text == kw_switch) return Tokens.KWSWITCH;
                    break;
                case 't':
                    if (text == kw_throw) return Tokens.KWTHROW;
                    if (text == kw_true) return Tokens.KWTRUE;
                    break;
                case 'v':
                    if (text == kw_void) return Tokens.KWVOID;
                    if (text == kw_var) return Tokens.KWVAR;
                    break;
                case 'w':
                    if (text == kw_while) return Tokens.KWWHILE;
                    break;
                default:
                    break;
            }
            return Tokens.IDENTIFIER;
        }

        public static IList<Declaration> GetDeclarationsForToken(Tokens token)
        {
            IList<Declaration> declarations = new List<Declaration>();
            foreach (string stringToken in GetTokens(token))
                declarations.Add(new Declaration(GetDescriptionForToken(stringToken), stringToken, (int)GetGlyphForToken(token) | (int)GetVisibilityForToken(token), stringToken));
            return declarations;
        }

        public static GlyphVisibility GetVisibilityForToken(Tokens token)
        {
            return GlyphVisibility.Global;
        }

        public static Glyphs GetGlyphForToken(Tokens token)
        {
            switch (token)
            {
                case Tokens.error:
                    return Glyphs.Conflict;
                case Tokens.IDENTIFIER:
                    return Glyphs.Field;
                case Tokens.NUMBER:
                    return Glyphs.Enum;
                case Tokens.VARIABLE:
                    return Glyphs.Field;
                case Tokens.TYPEIDENTIFIER:
                    return Glyphs.Class;
                case Tokens.TYPEREFERENCEIDENTIFIER:
                    return Glyphs.Class;
                case Tokens.MEMBERIDENTIFIER:
                    return Glyphs.Method;
                case Tokens.KWARRAY:
                    return Glyphs.Class;
                case Tokens.BUILTIN_FUNCTION:
                    return Glyphs.Method;
                default:
                    return Glyphs.Template;
            }
        }

        private static string GetDescriptionForToken(string stringToken)
        {
            Tokens token = GetToken(stringToken);
            switch (token)
            {
                case Tokens.BEGIN_CODE:
                case Tokens.ALTERNATE_BEGIN_CODE:
                    return "Begin Php Script";
                case Tokens.END_CODE:
                    return "Ends Php Script";
                case Tokens.KWCLASS:
                    return "Create a new class";
                case Tokens.KWFUNCTION:
                    return "Create a new function";
                case Tokens.KWINTERFACE:
                    return "Create a new interface";
                case Tokens.KWNULL:
                    return kw_null;
                case Tokens.KWABSTRACT:
                    return "Declares the class or function as abstract";
                case Tokens.KWIF:
                    return "Starts a new conditional block statement";
                case Tokens.KWELSE:
                    return "Starts a new statement if condition was not verified";
                case Tokens.KWELSEIF:
                    return "Starts a new conditional block if previous condition was not verified";
                case Tokens.KWWHILE:
                    return "Starts a new loop valid when condition is";
                case Tokens.KWFOR:
                    return "Starts a new loop with where a condition to loop, an initialization and a step may be specified";
                case Tokens.KWCONTINUE:
                    return "Step over";
                case Tokens.KWBREAK:
                    return "Break the loop";
                case Tokens.KWRETURN:
                    return "Stop the current execution and return a value if specified";
                case Tokens.KWFOREACH:
                    return "Starts a new loop on an array or object";
                case Tokens.KWAS:
                    return kw_as;
                case Tokens.KWECHO:
                    return "Prints the specified text to the current output stream";
                case Tokens.KWSWITCH:
                    return "Starts a new alternative statement";
                case Tokens.KWCASE:
                    return "Starts a new possibility in an alternative statement";
                case Tokens.KWDEFAULT:
                    return "Starts the default possibility in an alternative statement";
                case Tokens.KWSTATIC:
                    return "Declares the function or variable as static";
                case Tokens.KWINT:
                    return kw_int;
                case Tokens.KWVOID:
                    return kw_void;
                case Tokens.KWGLOBAL:
                    return "Declares the variable as global (accessible in any other script file)";
                case Tokens.KWVAR:
                case Tokens.KWPUBLIC:
                    return "Declares the function or variable as public (accessible in other instances)";
                case Tokens.KWPROTECTED:
                    return "Declares the function or variable as protected (accessible in other instances of the same class or subclass)";
                case Tokens.KWPRIVATE:
                    return "Declares the function or variable as private (accessible in other instances of the same class)";
                case Tokens.KWREQUIRE:
                case Tokens.KWINCLUDE:
                    return "Include another file script";
                case Tokens.KWREQUIREONCE:
                case Tokens.KWINCLUDEONCE:
                    return "Include another file script if not already included before";
                case Tokens.KWTHIS:
                    return "References the current instance";
                case Tokens.KWPARENT:
                    return "References the parent class";
                case Tokens.KWNEW:
                    return "Creates a instance of the specified class";
                case Tokens.KWTHROW:
                    return "Throws an Exception";
                case Tokens.ACCESSOR:
                    return "Accesses to a member function or variable";
                case Tokens.CLASSACCESSOR:
                    return "Accesses to a static function or variable";
                case Tokens.INHERIT:
                    return "Extends a class";
                case Tokens.IMPLEMENT:
                    return "Implements one or many interface";
                case Tokens.KWTRUE:
                    return kw_true;
                case Tokens.KWFALSE:
                    return kw_false;
                case Tokens.BUILTIN_FUNCTION:
                    return builtInFunction[stringToken];
                case Tokens.EQ:
                    return "Returns true if left expression equals the right expression";
                case Tokens.NEQ:
                    return "Returns true if left expression does not equal the right expression";
                case Tokens.TYPEEQ:
                    return "Returns true if left expression equals the right expression and the type of the leftexpression is the same as the right expression one";
                case Tokens.GT:
                    return "Returns true if left expression is greater than the right expression";
                case Tokens.GTE:
                    return "Returns true if left expression is greater than or equals the right expression";
                case Tokens.LT:
                    return "Returns true if left expression is lesser than the right expression";
                case Tokens.LTE:
                    return "Returns true if left expression is lesser than or equals the right expression";
                case Tokens.AMPAMP:
                    return "Returns true if left expression and the right expression are true";
                case Tokens.BARBAR:
                    return "Returns true if left expression or the right expression are true";
                case Tokens.KWINSTANCEOF:
                    return "Returns true if the variable is an instance of the specified class or subclass, or if the variable implements the specified interface";
                case Tokens.SELFCONCAT:
                    return "Joins the string with the existing string in the variable";
                case Tokens.MAP:
                    return "Creates a new association between the left and the right objects";
                default:
                    return stringToken;
            }
        }
    }
}
